package com.example.user.service.login.impl;

import cn.hutool.core.lang.Assert;
import com.example.framework.common.exception.ServiceException;
import com.example.framework.common.util.json.JsonUtils;
import com.example.framework.security.core.LoginUser;
import com.example.framework.security.core.dto.JwtTokenRespDto;
import com.example.framework.security.core.util.JwtTokenUtils;
import com.example.user.constants.ErrorCodeConstants;
import com.example.user.constants.LoginTypeEnum;
import com.example.user.controller.auth.vo.LoginReqVO;
import com.example.user.service.login.LoginService;
import com.example.user.service.user.UserDetailsServiceImpl;
import jakarta.annotation.Resource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Service;

@Service
public class PasswordLoginServiceImpl implements LoginService {

    @Resource
    private AuthenticationManager authenticationManager;

    @Resource
    private JwtTokenUtils jwtTokenUtils;

    /**
     * {@link ProviderManager#authenticate(Authentication)}(AuthenticationManager)
     * <p>
     * --> {@link AbstractUserDetailsAuthenticationProvider#authenticate(Authentication)}(AuthenticationProvider)
     * <p>
     * --> {@link DaoAuthenticationProvider#retrieveUser(String, UsernamePasswordAuthenticationToken)}(AbstractUserDetailsAuthenticationProvider)
     * <p>
     * --> {@link UserDetailsServiceImpl#loadUserByUsername(String)}(UserDetailsService)
     * <p>
     * --> {@link AbstractUserDetailsAuthenticationProvider#additionalAuthenticationChecks}(UserDetailsService)
     *
     * @param loginReqVO 登录参数
     * @return JWT Token
     */
    @Override
    public JwtTokenRespDto login(LoginReqVO loginReqVO) {
        String password = loginReqVO.getPassword();
        Assert.isTrue(password != null && password.length() >= 8, "密码格式错误");

        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(JsonUtils.toJsonString(loginReqVO), password);
        Authentication authenticate;
        try {
            authenticate = authenticationManager.authenticate(authenticationToken);
        } catch (AuthenticationException e) {
            throw ServiceException.of(ErrorCodeConstants.LOGIN_ERROR);
        }
        LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
        return jwtTokenUtils.generateTokenAndRefreshToken(loginUser);
    }

    @Override
    public LoginTypeEnum getType() {
        return LoginTypeEnum.BY_PASSWORD;
    }
}
